static const char *TAG = "gps";
#define ENABLE_UI 1
#include <thread>
#include <ctime>
#include <mutex>
#include <condition_variable>
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <ctime>

#include <Arduino.h>
#include <Wire.h>
#include <TFT_eSPI.h> // Hardware-specific library

#include "button.h"
#include "esp_log.h"

#if ENABLE_UI
#include "my_lvgl.h"
#endif

#include "currentmgr/Ina226App.h"
#include "c3log.h"
using namespace std;
using namespace std::chrono;

#define PIN_INPUT 9     // boot key/IO9

#if ENABLE_UI
lv_ui guider_ui;
lv_ui* ui;
lv_obj_t *IvpView; // I,V,P
lv_obj_t *spendTimeView;    //time
lv_obj_t *view_mWh;
lv_obj_t *view_mAh;
lv_obj_t *view_mV;
lv_obj_t *view_mA;
lv_obj_t *view_mW;

lv_chart_series_t *ser;
#endif

static lv_obj_t * chart;
/* Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv*/
static const lv_coord_t ecg_sample[] = {    // 400
    -2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -107, -107, -107, -114, -118, -117,
    -112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10, 4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
    13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25, 14, 15, 19, 28, 31, 26, 23, 25, 31,
    39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33, 19, -1, -27, -55, -67, -72, -71, -63,
    -49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288, 274, 255, 212, 173, 143, 117, 82, 39,
    -13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -123, -123, -129, -139, -148, -153,
    -159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -473, -517, -556, -592, -612, -620,
    -620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -222, -167, -114, -70, -47, -28, -4, 12,
    38, 52, 58, 56, 56, 57, 68, 77, 86,
    -2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -107, -107, -107, -114, -118, -117,
    -112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10, 4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
    13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25, 14, 15, 19, 28, 31, 26, 23, 25, 31,
    39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33, 19, -1, -27, -55, -67, -72, -71, -63,
    -49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288, 274, 255, 212, 173, 143, 117, 82, 39,
    -13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -123, -123, -129, -139, -148, -153,
    -159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -473, -517, -556, -592, -612, -620,
    -620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -222, -167, -114, -70, -47, -28, -4, 12,
    38, 52, 58, 56, 56, 57, 68, 77, 86,
};

#define CHART_SIZE (400)
#define BUF_DUAL_SIZE (CHART_SIZE)
static lv_coord_t ecg_sampleAB[BUF_DUAL_SIZE * 2] = {0};    // sec1: sec2: sec3: r r w
static int  ecg_sampleAB_Corse = 0;
static int displayStartId = 0;     // start

static void slider_x_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    int32_t v = lv_slider_get_value(obj);
    lv_chart_set_zoom_x(chart, v);
}

static void slider_y_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    int32_t v = lv_slider_get_value(obj);
    lv_chart_set_zoom_y(chart, v);
}

// INA226
Ina226App gInaApp;
static time_t start_t;

// display  trigger
mutex mt;
condition_variable cond;

#define TIME_ZONE (+8)   //Beijing Time
#define YEAR_BASE (2000) //date in GPS starts from 2000

class Semaphore {
public:
    Semaphore(long count = 0) : count(count) {}
    //V操作，唤醒
    void signal()
    {
        unique_lock<mutex> unique(mt);
        ++count;
        if (count <= 0)
            cond.notify_one();
    }
    //P操作，阻塞
    void wait()
    {
        unique_lock<mutex> unique(mt);
        --count;
        if (count < 0)
            cond.wait(unique);
    }
    
private:
    mutex mt;
    condition_variable cond;
    long count;
};

Semaphore sem(0);

/**
 * @brief Current Event Handler
 *
 * @param event_handler_arg handler specific arguments
 * @param event_base event base, here is fixed to ESP_NMEA_EVENT
 * @param event_id event id
 * @param event_data event specific arguments
 */
static void current_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    switch (event_id) {
    case 0:
        ESP_LOGW(TAG, "Unknown statement:%s", (char *)event_data);
        break;
    default:
        break;
    }
}

void syncLoop(void) {
    ESP_LOGI(TAG, "starting...");
    while (1) {
        delay(33);         // 30fps
        sem.signal();
    }
}

/* 定义积分函数 */
double integral(float* signal, int len) {
    double area = 0;  // 定义积分结果变量

    for (int i = 0; i < len; i++) {
        // area += (signal[i-1] + signal[i]) * 0.5;  // 使用梯形法计算积分
        area += signal[i];
    }
    // TODO = sum - (start + end) / 2

    return area;
}

struct CurPowerStatus {
    float cur = 0.0;    // 电流 A
    float vol = 0.0;    // V
    float power = 0.0;  // W
};

struct HistPowerStatus {    // 历史保存
    float cur[CHART_SIZE];    // 电流
    float vol[CHART_SIZE];
    float power[CHART_SIZE];
};

static struct CurPowerStatus ps;        // 当前 power status
static struct HistPowerStatus hist_ps;  // 历史 power status

static double energe_mWh = 0.0, energe_mAh = 0.0, fps = 0.0;
uint64_t sampleCnt = 0;
auto start_time = high_resolution_clock::now();

void IVP_Loop(void) {
    static int i = 0;
    srand(10);
    while (1) {
        #if 0
        gInaApp.fastGetIVP(ps.cur, ps.vol, ps.power);
        #endif
        delay(10);
        if (i % 1000 == 0) {
            i = 0;
            LOGI("%.06lfA %.06lfV %.06lfW", ps.cur, ps.vol, ps.power);
        }
        hist_ps.cur[displayStartId] = ps.cur;
        hist_ps.vol[displayStartId] = ps.vol;
        hist_ps.power[displayStartId] = ps.power;
        energe_mWh += ps.power * 1000;
        energe_mAh += ps.cur * 1000;
        sampleCnt++;
        // set char Vol data to [displayStartId + CHART_SIZE]
        // display [displayStartId, displayStartId + CHART_SIZE]
        // ecg_sampleAB[displayStartId + CHART_SIZE] = ps.vol * 1000/6 + 1;    // MAX 6V
        ecg_sampleAB[displayStartId + CHART_SIZE] = rand() %  1000;
        printf("%u\n", ecg_sampleAB[displayStartId + CHART_SIZE]);
        displayStartId++;
        if (displayStartId >= CHART_SIZE) {
            // move point and data to init position
            memcpy(ecg_sampleAB, ecg_sampleAB + CHART_SIZE, CHART_SIZE * sizeof(lv_coord_t));
            displayStartId = 0;
        }
        i++;
    }
}

void createServerThread() {
    new thread(syncLoop);
    #if 1
    new thread(IVP_Loop);
    #endif
}

// 短时间内连按一下
void onSwitchClickUp(){
    LOGI("key down!");
}

/**
 * Display 1000 data points with zooming and scrolling.
 * See how the chart changes drawing mode (draw only vertical lines) when
 * the points get too crowded.
 */
void lv_example_chart_5(void)
{
    /*Create a chart*/
    chart = lv_chart_create(ui->screen);
    // ui->screen_chart_1 = chart;
    lv_obj_set_size(chart, 240, 210);
    // lv_obj_align(chart, LV_ALIGN_CENTER, 0, -30);
    // lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
    // add chart 设置chart 格式
    // change type
    lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
    lv_chart_set_type(chart, LV_CHART_TYPE_LINE);
	lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 200);
    lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_X, 0, 200);
    // 修改栅格线数量、颜色
	lv_chart_set_div_line_count(chart, 7, 3);
    lv_obj_set_style_line_color(chart, lv_palette_main(LV_PALETTE_BLUE_GREY), LV_PART_MAIN);
    lv_obj_set_style_line_dash_width(chart, 1, LV_PART_MAIN);   // 虚线
    lv_obj_set_style_line_dash_gap(chart, 5, LV_PART_MAIN);

    lv_obj_set_style_bg_color(chart, lv_color_make(0x00, 0x00, 0x00), LV_PART_MAIN);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 5, 3, 4/*主刻度数*/, 10/*小刻度数*/, true, 40);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 5, 3, 3/*主刻度数*/, 10/*小刻度数*/, true, 50);

    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000);    // 0->1000
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 1000);    // 0->1000

    /*Do not display points on the data*/
    lv_obj_set_style_size(chart, 0, LV_PART_INDICATOR);

    ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);

    uint32_t pcnt = sizeof(ecg_sample) / sizeof(ecg_sample[0]);
    lv_chart_set_point_count(chart, 200);
}

void onCreate() {
    #if ENABLE_UI
    lvgl_setup();

    ui = &guider_ui;
    spendTimeView = ui->screen_label_1;
    // chart = ui->screen_chart_1; // not use it, change to create dynimic
    // view_mWh = ui->screen_label_mWh;
    // view_mAh = ui->screen_label_mAh;
    view_mV = ui->screen_label_V;
    view_mA = ui->screen_label_A;
    // view_mW = ui->screen_label_mW;
    #endif

    // 重新创建chart
    #if 0
    for (int i = 0; i < 95; i++) {
         lv_chart_set_next_value(chart, screen_chart_2_0, i * 2);
    }
    lv_chart_set_next_value(chart, screen_chart_2_0, 100);
    lv_chart_set_next_value(chart, screen_chart_2_0, 150);
    #else
    lv_example_chart_5();
    #endif

    // init time
    time(&start_t);
    // create server thread
    createServerThread();

    // button
    pinMode(PIN_INPUT, INPUT);
    // button.attachClick(onSwitchClick);
    init_button(onSwitchClickUp);
}

void setViewText(lv_obj_t * lv_obj, const char *format, ...) {
    char temp[64] = {0};
    va_list vlArgs;
    va_start(vlArgs, format);
    vsnprintf(temp, sizeof(temp) - 1, format, vlArgs);
    va_end(vlArgs);

    lv_label_set_text(lv_obj, temp);
}

void onDraw() {
    char temp[64] = {0};
#if ENABLE_UI
    // show speed time
    time_t end_t;
    time(&end_t);
    int diff_s = (int)difftime(end_t, start_t);
    setViewText(spendTimeView, "%02d:%02d", diff_s / 60 , diff_s % 60);     // timeView
    // setViewText(IvpView, "%.01lfA %.01lfV %.01lfW", ps.cur, ps.vol, ps.power);
    // setViewText(view_mWh, "%.1lf", energe_mWh / sampleCnt * diff_s / 3600);
    // setViewText(view_mAh, "%.1lf", energe_mAh / sampleCnt * diff_s / 3600);
    if (ps.vol > 1) {
        setViewText(view_mV, "%.1lf", ps.vol * 1000);
    } else {
        setViewText(view_mV, "%.3lf", ps.vol * 1000);
    }
    if (ps.cur > 1) {
        setViewText(view_mA, "%.1lf", ps.cur * 1000);
    } else {
        setViewText(view_mA, "%.3lf", ps.cur * 1000);
    }
    // setViewText(view_mW, "%.3lf", ps.power * 1000);
    // chart
    lv_chart_set_ext_y_array(chart, ser, (lv_coord_t *)(ecg_sampleAB + displayStartId));
#else
    LOGI("%.01lfA %.01lfV %.01lfW", cur, vol, power);
#endif
}

void setup(void) {
    Serial.begin(115200);
    // INA
    #if 1
    int ret = gInaApp.setup();
    if (0 == ret) {
        LOGI("%s gInaApp init suc\n", __func__);
    } else {
        LOGE("%s gInaApp init failed\n", __func__);
    }
    #endif
    // display
    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);
    pinMode(11, PULLDOWN);
    // digitalWrite(11, LOW);
    onCreate();
}

void loop() {
    sem.wait();         // wait time or update
    onDraw();           // update
    #if ENABLE_UI
    lvgl_loop_func();   // flush
    #endif
    // LOGI("loop");
}
